package com.lcf.common.util;

import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.StreamProgress;
import cn.hutool.core.lang.Console;
import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.channel.ChannelShell;
import org.apache.sshd.client.channel.ClientChannelEvent;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.util.io.input.NoCloseInputStream;
import org.apache.sshd.common.util.io.output.NoCloseOutputStream;
import org.apache.sshd.sftp.client.SftpClient;
import org.apache.sshd.sftp.client.SftpClientFactory;

import java.io.*;
import java.util.EnumSet;
import java.util.StringJoiner;
import java.util.function.Consumer;

public class FTPTest {

    static SftpClient sftp;

    public static void main(String[] args) {
        String name = "root";
        String password = "******";
        int port = 22;
        String host = "******";

        try (SshClient client = SshClient.setUpDefaultClient()) {
            client.start();
            try (ClientSession session = client.connect(name, host, port).verify().getSession()) {
                session.addPasswordIdentity(password);
                boolean success = session.auth().verify().isSuccess();
                if (success) {
                    sftp = SftpClientFactory.instance().createSftpClient(session);
                    //
                    Iterable<SftpClient.DirEntry> dirEntries = sftp.readDir("/");
                    StringJoiner sj = new StringJoiner("\n");
                    dirEntries.forEach(dirEntry -> {
                        SftpClient.Attributes attributes = dirEntry.getAttributes();
                        String format = String.format(" %s %s %s \t", dirEntry.getFilename(),
                                attributes.getModifyTime(),
                                attributes.getSize());
                        sj.add(format);
                    });
                    Console.log(sj.toString());

                    // 重命名
                    //rename("/root/yun-2022.1.5.jar","/root/yun-2022.1.5.new.jar");
                    //rename("/apps/jdkddddd","/apps/jdk");


                    // 删除文件夹
                    //sftp.rmdir("/apps/jdk");
                    // 删除文件
                    //sftp.remove();

                    // 创建文件夹
                    //sftp.mkdir("/333");

                    /*

                    // 下载案例
                    download("/apps/jdk1.8/openlogic-openjdk-8u292-b10-linux-x64/src.zip",
                            "F:/src.zip", aLong -> Console.log("已下载：{}", aLong));
                    // 上传案例
                    upload("/apps/cat.mp4", "C:\\Users\\Administrator\\Downloads\\猫1.mp4",
                            aLong -> Console.log("已上传：{}", aLong));

                            */

                    // 交互式命令
                    try (ChannelShell channel = session.createShellChannel()) {
                        channel.setIn(new NoCloseInputStream(System.in));
                        channel.setOut(new NoCloseOutputStream(System.out));
                        channel.setErr(new NoCloseOutputStream(System.err));
                        channel.open();
                        channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), 0);
                    } finally {
                        session.close(false);
                    }

                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*重命名文件夹 或文件 */
    private static void rename(String oldPath, String newPath) throws IOException {
        sftp.rename(oldPath, newPath);
    }

    private static void upload(String input, String output, Consumer<Long> progress) {
        try (
                OutputStream outputStream = sftp.write(input);
                FileInputStream inputStream = new FileInputStream(output);
        ) {
            copy(inputStream, outputStream, progress);
        } catch (IOException | IORuntimeException e) {
            throw new RuntimeException(e);
        }
    }

    private static void download(String input, String output, Consumer<Long> progress) {
        try (
                InputStream inputStream = sftp.read(input);
                FileOutputStream outputStream = new FileOutputStream(output)
        ) {
            copy(inputStream, outputStream, progress);
        } catch (IOException | IORuntimeException e) {
            throw new RuntimeException(e);
        }
    }

    private static void copy(InputStream in, OutputStream out, Consumer<Long> progress) {
        IoUtil.copy(in, out, 1024, new StreamProgress() {
            @Override
            public void start() {
                System.out.println("start ... ");
            }

            @Override
            public void progress(long progressSize) {
                progress.accept(progressSize);
            }

            @Override
            public void finish() {
                System.out.println("finish ... ");
            }
        });
    }
}
